import datetime

from decimal import Decimal

from database import db_session

from flask import session

from sqlalchemy import exc
from sqlalchemy import or_

from sqlalchemy.sql.expression import func
import managers.usuarios_mgr

from models import *

#Metodos

def listar_proyectos(id_usuario):
    """Devuelve la lista de Proyectos del sistema, asociados al usuario
    @param id_usuario: Id del usuario logueado@return items
    @return items: retorna la lista de proyectos"""
    
    usuario = db_session.query(Usuario).filter_by(id_usuario = id_usuario).one()
    proyectos = db_session.query(Proyecto).filter_by(lider = usuario.id).all()

    items = []

    for fila_proyecto in proyectos:
        item = dict(nombre=fila_proyecto.nombre, descripcion=\
        fila_proyecto.descripcion, observacion=fila_proyecto.observacion, \
        estado=fila_proyecto.estado, presupuesto=fila_proyecto.presupuesto)

        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def verificar_parametros_crear_proyecto(nombre, descripcion, presupuesto):
    """Realiza la validaciones de los parametros ingresados para 
    el nuevo proyecto
    @param nombre: Nombre ingresado para el proyecto
    @param descripcion: Descripcion ingresada para el proyecto
    @param presupuesto: Presupuesto ingresado para el proyecto"""
    
    resultado = True

    if nombre == "":
        resultado = False
    elif descripcion == "":
        resultado = False
    elif presupuesto == "":
        resultado = False

    return resultado

def verificar_valor_presupuesto(presupuesto):
    """Verifica que el presupuesto ingresado sea numericamente 
    valido
    @param presupuesto: Valor del presupuesto del proyecto"""
    
    try:
        resultado = Decimal(presupuesto)
    except:
        return False

    return True

def insertar_proyecto(id_usuario, nombre, descripcion, observacion, presupuesto):
    """Realiza la insercion de un proyecto en la tabla Proyectos
    @param id_usuario: Nombre del usuario logueado
    @param nombre: Nombre del nuevo proyecto
    @param descripcion: Descripcion del nuevo proyecto
    @param observacion: Observacion del nuevo proyecto
    @param presupuesto: Presupuesto del nuevo proyecto"""
    
    try:
        proy_test = db_session.query(Proyecto). \
        filter_by(nombre=nombre).one()

        return 'El proyecto ya existe'
    except exc.SQLAlchemyError:
        pass

    try:
        #Buscamos el pk del lider de proyecto
        lider = db_session.query(Usuario).filter_by(id_usuario=id_usuario).one()

        #Fecha actual
        fecha_actual = datetime.now()

        proyecto = Proyecto()
        proyecto.nombre = nombre
        proyecto.descripcion = descripcion
        proyecto.observacion = observacion
        proyecto.presupuesto = Decimal(presupuesto)
        proyecto.estado = 'PEN'
        proyecto.fecha_creacion = fecha_actual
        proyecto.lider = lider.id
        #Se registra al lider como miembro del proyecto recien creado
        proyecto.miembros.append(lider)
        #Se registra al lider como miembro del comite del proyecto recien creado
        proyecto.miembros_comite.append(lider)
        proyecto.fecha_modificacion = fecha_actual
        proyecto.usuario_modificacion = lider.id
        db_session.add(proyecto)
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return 'OK'

def validaciones_administrar_miembros(seleccionados):
    """Verifica que haya sido seleccionado un proyecto, y solo uno
    @param seleccionados: Lista de miembros seleccionados
    @return error: mensaje de error en caso de no seleccionar ni un
                   proyecto o seleccionar mas de uno"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    return error

def listar_miembros():
    """Devuelve la lista de usuarios miembros del proyecto
    @return items: lista los miembros de un proyecto"""
    
    nombre_proyecto = session['nombre_proyecto']
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    miembros = proyecto.miembros

    items = []
    for fila_miembro in miembros:
        usuario = db_session.query(Usuario).filter_by(id=\
        fila_miembro.id).one()

        if usuario.estado == "ACT":
            item = dict(id_usuario=usuario.id_usuario, \
            nombre=usuario.nombre, apellido=usuario.apellido, \
            correo=usuario.correo)

            items.append(item)

    items = sorted(items, key=lambda elemento: elemento['id_usuario'])
    return items

def validaciones_asignar_miembro(seleccionados):
    """Verifica que el dato haya sido seleccionado y que el mismo 
    corresponda a uno o mas usuarios del sistema
    @param seleccionados: Lista de usuarios seleccionados
    @return error: mensaje de error si no ha sido seleccionado ni un usuario"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun usuario
        error = "Debe seleccionar al menos un usuario"
        return error

    return error

def validaciones_desasignar_miembro(seleccionados):
    """Verifica que el dato haya sido seleccionado y que el mismo corresponda 
    a un solo usuario o mas miembros del proyecto. Ademas verifica que el 
    miembro a ser eliminado no sea el lider del proyecto
    @param seleccionados: recibe la lista de usuarios que fueron 
                          seleccionados.
    @return error: retorna un mensaje indicando si no se ha seleccionado
                    al menos un usuario. Asi tambien verifica que entre
                    los seleccionados no se encuentre el lider del 
                    proyecto"""
                    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun usuario
        error = "Debe seleccionar un usuario"
        return error

    nombre_proyecto = session['nombre_proyecto']
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    usuario = db_session.query(Usuario).filter_by(id=\
    proyecto.lider).one()

    for elemento in seleccionados:
        if elemento == usuario.id_usuario:
            error = "El lider del proyecto no puede desasignarse"
            return error

    lista_miembros_comite = proyecto.miembros_comite
    for elemento in seleccionados:
        for miembro_comite in lista_miembros_comite:
            if elemento == miembro_comite.id_usuario:
                error = "Un miembro del comite no puede desasignarse"
                return error

    return error

def asignar_miembro(seleccionados):
    """Asigna uno o mas usuarios a un proyecto determinado
    @param seleccionados: Lista de usuarios seleccionados"""
    
    try:
        nombre_proyecto = session["nombre_proyecto"]
        proyecto = db_session.query(Proyecto).filter_by(nombre=\
        nombre_proyecto).one()

        for elemento in seleccionados:
            usuario = db_session.query(Usuario).filter_by(id_usuario=\
            elemento).one()

            proyecto.miembros.append(usuario)
            db_session.add(proyecto)
            db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
    return 'OK'

def desasignar_miembro(seleccionados):
    """Desasigna uno o mas usuarios de un proyecto determinado
    @param seleccionados: recibe la lista de usuarios que fueron 
                          seleccionados."""
                          
    try:
        nombre_proyecto = session["nombre_proyecto"]
        proyecto = db_session.query(Proyecto).filter_by(nombre=\
        nombre_proyecto).one()

        for elemento in seleccionados:
            usuario = db_session.query(Usuario).filter_by(id_usuario=\
            elemento).one()

            #Se eliminan los roles asignados al usuario en ese proyecto
            roles_asignados = usuario.roles
            for rol_asignado in list(roles_asignados):
                usuario.roles.remove(rol_asignado)
                db_session.flush()

            #Se elimina al usuario como miembro del proyecto
            proyecto.miembros.remove(usuario)
            db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
    return 'OK'

def buscar_miembros(cadena, campos):
    """Realiza la busqueda de los miembros y devuelve las conincidencias
    encontradas
    @param cadena: indica el dato que se quiere buscar
    @param campo: indica por cual campo se va a buscar
    @return items: retorna la lista con las coincidencias"""
    
    items_auxiliar = []
    items_auxiliar = managers.usuarios_mgr.buscar_usuarios(cadena, campos)

    nombre_proyecto = session['nombre_proyecto']
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    miembros = proyecto.miembros

    items = []
    for elemento in items_auxiliar:
        for usuario_miembro in miembros:
            if usuario_miembro.id_usuario == elemento["id_usuario"]:
                items.append(elemento)
                break

    items = sorted(items, key=lambda elemento: elemento['id_usuario'])
    return items

def validaciones_cancelar_proyecto(seleccionados):
    """Verifica que se haya seleccionado un proyecto, y solo uno, 
    ademas de que el mismo no se encuentre en estado ACT. Recibe 
    como parametro una lista de proyectos seleccionados
    @param seleccionados: Lista de proyectos seleccionados
    @return error: mensaje de erorr que indica si no se ha seleccionado 
                   un proyecto o se ha seleccionado mas de uno"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    nombre_proyecto = seleccionados[0]
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    if proyecto.estado != "PEN":
        error = "No se puede cancelar un proyecto ya iniciado"
        return error

    return error

def listar_no_miembros():
    """Devuelve la lista de usuarios no miembros del proyecto
    @return items: retorna la lista de no miembros del proyecto"""
    
    nombre_proyecto = session['nombre_proyecto']
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    miembros = proyecto.miembros

    usuarios = db_session.query(Usuario).filter_by(tipo=3).order_by\
    (Usuario.id_usuario).all()

    items = []
    for fila_usuario in usuarios:
        coincide = False
        for usuario_miembro in miembros:
            if fila_usuario.id == usuario_miembro.id:
                coincide = True

        if not coincide:
            item = dict(id_usuario=fila_usuario.id_usuario, \
            nombre=fila_usuario.nombre, apellido=fila_usuario.apellido, \
            correo=fila_usuario.correo)

            items.append(item)

    items = sorted(items, key=lambda elemento: elemento['id_usuario'])
    return items

def buscar_no_miembros(cadena, campos):
    """Realiza la busqueda de los no miembros y devuelve las 
    conincidencias encontradas
    @param cadena: indica el dato que se quiere buscar
    @param campo: indica por cual campo se va a buscar
    @return items: devuelve la lista con las coincidencias encontadas"""
    
    items_auxiliar = []
    items_auxiliar = managers.usuarios_mgr.buscar_usuarios(cadena, campos)

    nombre_proyecto = session['nombre_proyecto']
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    miembros = proyecto.miembros

    items = []
    for elemento in items_auxiliar:
        coincide = False
        for usuario_miembro in miembros:
            if elemento['tipo'] != 3:
                coincide = True

            if usuario_miembro.id_usuario == elemento["id_usuario"]:
                coincide = True

        if not coincide:
            items.append(elemento)

    items = sorted(items, key=lambda elemento: elemento['id_usuario'])
    return items

def cancelar_proyecto(nombre_proyecto):
    """Elimina de la base de datos el proyecto con el nombre 
    nombre_proyecto, recibido como parametro
    @param nombre_proyecto: Nombre del proyecto a eliminar"""
    
    try:
        proyecto = db_session.query(Proyecto).filter_by(nombre=\
        nombre_proyecto).one()

        db_session.delete(proyecto)
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
    return 'OK' 

def validaciones_render_asignar_roles(seleccionados):
    """Verifica que se haya seleccionado un miembro, y solo uno. Recibe 
    como parametro una lista de miembros seleccionados
    @param seleccionados: Lista de miembros seleccionados
    @return error:mensaje de error que indica si no fue seleccionado ni un 
                  usuario o mas de un usuario"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun miembro
        error = "Debe seleccionar un usuario"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un miembro
        error = "Debe seleccionar un unico usuario"
        return error

    return error

def validaciones_asignar_roles(seleccionados):
    """Verifica que se haya seleccionado al menos un rol. Recibe 
    como parametro una lista de roles seleccionados
    @param seleccionados: Lista de roles seleccionados
    @return error: mensaje de error que indica si fue seleccionado al 
                   menos un rol"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun rol
        error = "Debe seleccionar al menos un rol"
        return error

    return error

def listar_roles_no_asignados():
    """Lista los roles disponibles en ese proyecto para el usuario 
    seleccionado
    @return items: retorna la lista de roles no asignados"""
    
    id_usuario_seleccionado = session['id_usuario_seleccionado']
    nombre_proyecto = session['nombre_proyecto']

    usuario = db_session.query(Usuario).filter_by(id_usuario=\
    id_usuario_seleccionado).one()

    roles_del_usuario = usuario.roles

    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    fases = db_session.query(Fase).filter_by(fk_proyecto=\
    proyecto.id).all()

    roles_de_proyecto = []
    for fase in fases:
        roles = db_session.query(Rol).filter_by(fk_fase=\
        fase.id).all()
        for rol in roles:
            roles_de_proyecto.append(rol.id)

    items = []
    for rol_proyecto in roles_de_proyecto:
        coincide = False
        for rol_usuario in roles_del_usuario:
            if rol_proyecto == rol_usuario.id:
                coincide = True
                break

        if not coincide:
            rol = db_session.query(Rol).filter_by(id=\
            rol_proyecto).one()

            fase = db_session.query(Fase).filter_by(id=\
            rol.fk_fase).one()

            item = dict(id=rol.id, nombre=rol.nombre, \
            descripcion=rol.descripcion, observacion=\
            rol.observacion, fase=fase.nombre)

            items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def buscar_proyectos(id_usuario, cadena, campos):
    """Realiza la busqueda de los proyectos de acuerdo al filtro 
    seleccionado (nombre, descripcion, observacion, presupuesto, 
    estado) y devuelve las conincidencias encontradas
    @param id_usuario: Id del usuario logueado
    @param cadena: indica el dato que se quiere buscar
    @param campo: indica por cual campo se va a buscar
    @return items: retorna la lista de proyectos que coinciden con la busqueda"""
    
    usuario = db_session.query(Usuario).filter_by(id_usuario = id_usuario).one()
    items = []
    presupuesto = None
    if campos == "todos":

        if cadena.isdecimal() == True:
            presupuesto = Decimal(cadena)

        proyecto = db_session.query(Proyecto).filter_by(\
        lider=usuario.id).filter(or_(\
        func.lower(Proyecto.nombre).contains(cadena),\
        func.lower(Proyecto.descripcion).contains(cadena),\
        func.lower(Proyecto.observacion).contains(cadena),\
        Proyecto.presupuesto==presupuesto, \
        func.lower(Proyecto.estado).contains(cadena))).all()
    if campos == "nombre":
        proyecto = db_session.query(Proyecto).filter_by(\
        lider=usuario.id).filter(func.lower(Proyecto.nombre).contains(cadena)).all()
    if campos == "descripcion":
        proyecto = db_session.query(Proyecto).filter_by(\
        lider=usuario.id).filter(func.lower(Proyecto.descripcion).contains(cadena)).all()
    if campos == "observacion":
        proyecto = db_session.query(Proyecto).filter_by(\
        lider=usuario.id).filter(func.lower(Proyecto.observacion).contains(cadena)).all()
    if campos == "presupuesto":
        if verificar_valor_presupuesto(cadena):
            presupuesto = Decimal(cadena)
            proyecto = db_session.query(Proyecto).filter_by(\
            lider=usuario.id, presupuesto=presupuesto).all()
        else: #El valor no es un numero valido
            return items
            #Se retorna una lista vacia
    if campos == "estado":
        proyecto = db_session.query(Proyecto).filter_by(\
        lider=usuario.id).filter(func.lower(Proyecto.estado).contains(cadena)).all()

    for fila_proyecto in proyecto:
        item = dict(nombre=fila_proyecto.nombre, \
        descripcion=fila_proyecto.descripcion, observacion=fila_proyecto.observacion, \
        presupuesto=fila_proyecto.presupuesto, estado=fila_proyecto.estado)

        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def validaciones_iniciar_proyecto(seleccionados):
    """Verifica las condiciones para poder iniciar el proyecto
    @param seleccionados: lista de seleccionados para iniciar proyecto
    @return error: mensaje de error en caso de no pasar las validaciones"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    nombre_proyecto = seleccionados[0]
    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    if proyecto.estado != "PEN":
        error = "El proyecto debe estar en estado Pendiente"
        return error
    
    fases = db_session.query(Fase).filter_by(fk_proyecto = \
    proyecto.id).all()
    if len(fases)==0:
        error = "El proyecto debe tener al menos una Fase"
        return error
    return error

def iniciar_proyecto(seleccionado):
    """Realiza la accion de iniciar el proyecto
    @param seleccionados: lista de seleccionados para iniciar proyecto"""
    
    try:        
        nombre_proyecto = seleccionado
        proyecto = db_session.query(Proyecto).filter_by(nombre = \
        nombre_proyecto).one()

        lider = db_session.query(Usuario).filter_by(\
        id = proyecto.lider).one()
        fecha_actual = datetime.now()

        for fila_fase in proyecto.fases:
            fila_fase.estado = "PEN"

        proyecto.estado = "ACT"
        proyecto.fecha_modificacion = fecha_actual
        proyecto.usuario_modificacion = lider.id
        
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
        #return 'No se pudo insertar el usuario'

    return "OK"

def validaciones_finalizar_proyecto(seleccionados):
    """Verifica las condiciones para poder iniciar el proyecto
    @param seleccionados: lista de seleccionados para finalizar el proyecto
    @return error: mensaje de erroe en caso de no pasar las validaciones
                   correspondientes""" 
       
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    nombre_proyecto = seleccionados[0]
    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    if proyecto.estado == "PEN" or proyecto.estado == "FIN":
        error = "El proyecto debe estar con estado Activo"
        return error

    sw = False
    for fase in proyecto.fases:
        if fase.estado != "FIN":
            sw = True

    if sw == True:
        error = "Todas las fases del proyecto deben estar finalizadas"

    return error

def finalizar_proyecto(seleccionado, finalizacion):
    """Realiza la accion de finalizar el proyecto
    @param seleccionados: lista de seleccionados para finalizar el proyecto"""
    
    try:
        nombre_proyecto = seleccionado
        proyecto = db_session.query(Proyecto).filter_by(nombre = \
        nombre_proyecto).one()

        lider = db_session.query(Usuario).filter_by(\
        id = proyecto.lider).one()
        fecha_actual = datetime.now()        

        proyecto.estado = "FIN"
        proyecto.finalizacion = finalizacion
        proyecto.fecha_modificacion = fecha_actual
        proyecto.usuario_modificacion = lider.id
    
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return "OK"

def asignar_roles_usuario(seleccionados):
    """Asigna los roles seleccionados, al usuario miembro indicado.
    @param seleccionados: Recibe la lista de roles a asignar"""
    
    id_usuario_seleccionado = session['id_usuario_seleccionado']

    usuario = db_session.query(Usuario).filter_by(id_usuario=\
    id_usuario_seleccionado).one()

    try:
        for rol in seleccionados:
            rol = db_session.query(Rol).filter_by(id=int(rol)).one()
            usuario.roles.append(rol)
            db_session.add(usuario)
            db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return 'OK'

def listar_roles_asignados():
    """Lista los roles asignados al usuario seleccionado
    @return items: lista de roles asignados"""
    
    id_usuario_seleccionado = session['id_usuario_seleccionado']
    nombre_proyecto = session['nombre_proyecto']

    usuario = db_session.query(Usuario).filter_by(id_usuario=\
    id_usuario_seleccionado).one()

    roles_del_usuario = usuario.roles

    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    fases = db_session.query(Fase).filter_by(fk_proyecto=\
    proyecto.id).all()

    roles_de_proyecto = []
    for fase in fases:
        roles = db_session.query(Rol).filter_by(fk_fase=\
        fase.id).all()
        for rol in roles:
            roles_de_proyecto.append(rol.id)

    items = []
    for rol_proyecto in roles_de_proyecto:
        coincide = False
        for rol_usuario in roles_del_usuario:
            if rol_proyecto == rol_usuario.id:
                coincide = True
                break

        if coincide:
            rol = db_session.query(Rol).filter_by(id=\
            rol_proyecto).one()

            fase = db_session.query(Fase).filter_by(id=\
            rol.fk_fase).one()

            item = dict(id=rol.id, nombre=rol.nombre, \
            descripcion=rol.descripcion, observacion=\
            rol.observacion, fase=fase.nombre)

            items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def desasignar_roles_usuario(seleccionados):
    """Desasigna los roles seleccionados, al usuario miembro indicado.
    @param seleccionados: Recibe la lista de roles a desasignar"""
    
    id_usuario_seleccionado = session['id_usuario_seleccionado']

    usuario = db_session.query(Usuario).filter_by(id_usuario=\
    id_usuario_seleccionado).one()

    try:
        for elemento in seleccionados:
            rol = db_session.query(Rol).filter_by(id=int(elemento)).one()
            usuario.roles.remove(rol)
            db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return 'OK'
    
def validaciones_modificar_proyecto(seleccionados):
    """Validaciones realizadas antes de modificar un proyecto
    @param seleccionados: lista de seleccionados para modificar el proyecto
    @return error: mensaje de error en caso de no haber seleccionado un 
                   proyecto para modificar"""
    
    error = None
    if len(seleccionados) == 0:
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1:
        error = "Debe seleccionar un unico proyecto"
        return error
    
    return error

def modificar_proyecto(id_modificador, nombre, descripcion, observacion, presupuesto):
    """Realiza la accion de moificar el proyecto
    @param id_modificador: Id del usuario modificador
    @param nombre: nombre que se quiera modificar
    @param descripcion: descripcion que se quiera modificar
    @param observacio: observacion que se quiera modificar
    @param presupuesto: presupuesto que se quiera modificar"""

    try:
        usuario = db_session.query(Usuario).filter_by(
        id_usuario = id_modificador).one()
    
        nombre_proyecto = session['nombre_proyecto']
    
        proyecto = db_session.query(Proyecto).filter_by(nombre = \
        nombre_proyecto).one()
    
        fecha_actual = datetime.now()
        
        proyecto.nombre = nombre
        proyecto.descripcion = descripcion
        proyecto.observacion = observacion
        proyecto.presupuesto = Decimal(presupuesto)
        proyecto.fecha_modificacion = fecha_actual
        proyecto.usuario_modificacion = usuario.id
        
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
    
    return "OK"
    
def validaciones_parametros_modificar_proyecto(nombre_proyecto, \
p_nombre, p_descripcion, p_presupuesto):
    """Verifica que todos los parametros requeridos fueron ingresados
    @param nombre_proyecto: nombre del proyecto actual
    @param p_nombre: nombre del proyecto a modificar
    @param p_descripcion: descripcion del proyecto a modificar
    @param p_presupuesto: presupuesto del proyecto a modificar
    @return error: mensaje de error en caso de no ingresar los datos requeridos"""
    
    error = "OK"
    if p_nombre == "":
        error = "Se debe ingresar un nombre."
    elif p_descripcion == "":
        error = "Se debe ingresar la descripcion"
    elif len(p_presupuesto) == 0:
        error = "Se debe ingresar el presupuesto"
    elif len(p_presupuesto) > 0:
        sw = verificar_valor_presupuesto(p_presupuesto)
        if sw == False:
            error = "El presupuesto debe ser numerico"
    
    if nombre_proyecto != p_nombre:
        proyecto = db_session.query(Proyecto).filter(\
        func.lower(Proyecto.nombre) == func.lower(p_nombre))
        if proyecto is not None:
            error = "No se puede utilizar el nombre de proyecto ingresado"
            
    return error

def validaciones_administrar_fase(seleccionados):
    """Verifica que los parametros requeridos fueron ingresados
    @param seleccionados: lista de las fases que fueron seleccionados
    @return error: mensaje de error en caso de no seleccionar algun 
                   proyecto o haber seleccionado mas de uno."""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error
    return error
    
def obtener_estado(nombre_proyecto):
    """Obtiene el estado del proyecto
    @param nombre_proyecto: nombre del proyecto actual
    @return estado: retorna el estado de unproyecto"""
    
    estado = db_session.query(Proyecto.estado).filter_by( \
    nombre = nombre_proyecto).one()
    return estado

def listar_roles_proyecto():
    """Lista los roles definidos para el proyecto actual
    @return items: retorna la lista de roles del proyecto"""
    
    nombre_proyecto = session['nombre_proyecto']

    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    fases = proyecto.fases

    items = []
    for fase in fases:
        roles = fase.roles
        for rol in roles:
            item = dict(id=rol.id, nombre=rol.nombre, \
            descripcion=rol.descripcion, observacion=\
            rol.observacion, fase=fase.nombre)

            items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def validaciones_administrar_roles(seleccionados):
    """Verifica que se haya seleccionado un proyecto, y solo uno
    @param seleccionados: Lista de proyectos seleccionados
    @return error: retorna un mensaje de error en caso de no pasar las validaciones"""
    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error
    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    return error

def listar_fases_crear_roles():
    """Lista las fases del proyecto actual
    @return items: retorna la lista de fases."""
    
    nombre_proyecto = session['nombre_proyecto']

    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    fases = proyecto.fases

    items = []
    for fase in fases:
        item = dict(id=fase.id, nombre=fase.nombre)
        items.append(item)

    return items

def listar_permisos():
    """Devuelve una lista con todos los permisos del sistema
    @return items: retorna la lista de permisos"""
    
    items = []

    permisos = db_session.query(Permiso).order_by(Permiso.id).all()

    for permiso in permisos:
        item = dict(id=permiso.id, descripcion=permiso.descripcion)
        items.append(item)

    return items

def validaciones_boton_crear_rol(nombre_proyecto):
    """Valida que el proyecto tenga al menos una fase
    @param nombre_proyecto: Nombre del proyecto actual
    @return error: mensaje de error en caso de no pasar las validaciones"""
    
    error = None
    proyecto = db_session.query(Proyecto).filter_by(nombre=\
    nombre_proyecto).one()

    cant = db_session.query(Fase).filter_by(\
    fk_proyecto = proyecto.id).count()

    if cant == 0:
        error = "El proyecto no posee fases. Debe crear al menos una"
        return error

    return error

def verificar_parametros_crear_rol(nombre, descripcion, permisos):
    """Verifica que los parametros ingresados para el nuevo rol
    cumplen con todas las validaciones necesarias
    @param nombre: Nombre del nuevo rol
    @param descripcion: Descripcion del nuevo rol
    @param permisos: Lista de permisos del nuevo rol
    @return error: mensaje de error en caso de no pasar las validaciones"""
            
    error = None

    #El sistema verifica que los datos requeridos fueron ingresados
    if nombre == "":
        error = "Se debe ingresar un nombre"
        return error

    if descripcion == "":
        error = "Se debe ingresar una descripcion"
        return error

    #El sistema verifica que se haya seleccionado al menos un permiso
    if len(permisos) == 0: #No selecciono ningun permiso
        error = "Debe seleccionar al menos un permiso"
        return error

    #El sistema verifica que el nombre del rol sea unico en el proyecto
    nombre_proyecto = session['nombre_proyecto']

    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    fases = proyecto.fases

    for fase in fases:
        roles = fase.roles
        for rol in roles:
            if rol.nombre == nombre:
                error = "El nombre debe ser unico en el proyecto"
                break
    return error

def crear_rol(nombre, descripcion, observacion, fase, permisos):
    """Crea un nuevo rol para el proyecto y fase seleccionados, con
    los permisos dados
    @param nombre: Nombre del nuevo rol
    @param descripcion: Descripcion del nuevo rol
    @param observacion: Observacion del nuevo rol
    @param fase: Fase del nuevo rol
    @param permisos: Lista de permisos del nuevo rol"""
    
    try:
        fecha_actual = datetime.now()
        id_usuario = session['id_usuario']
        usuario = db_session.query(Usuario).filter_by\
        (id_usuario=id_usuario).one()

        rol = Rol()
        rol.nombre = nombre
        rol.descripcion = descripcion
        rol.observacion = observacion
        rol.fk_fase = int(fase)
        rol.fecha_creacion = fecha_actual
        rol.usuario_creacion = usuario.id
        rol.fecha_modificacion = fecha_actual
        rol.usuario_modificacion = usuario.id

        for permiso in permisos:
            perm = db_session.query(Permiso).filter_by\
            (id=int(permiso)).one()
            rol.permisos.append(perm)

        db_session.add(rol)
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return "OK"

def validaciones_modificar_rol(seleccionados):
    """Valida que se ha seleccionado un rol, y solo uno, para la
    modificacion del mismo
    @param seleccionados: Lista de roles seleccionados
    @return error: mensaje de error en caso de no pasar las validaciones"""
    
    error = None

    if len(seleccionados) == 0: #No selecciono ningun rol
        error = "Debe seleccionar un rol"
        return error

    if len(seleccionados) > 1: #Selecciono mas de un rol
        error = "Debe seleccionar un solo rol"
        return error

    return error

def verificar_parametros_modificar_rol(nombre, descripcion, permisos):
    """Verifica que los parametros ingresados para el rol a modificar 
    cumplen con todas las validaciones necesarias
    @param nombre: Nombre del rol a modificar
    @param descripcion: Descripcion del rol a modificar
    @param permisos: Lista de permisos del rol a modificar
    @return error: mensaje de error en caso de no pasar las validaciones"""
    
    error = None

    #El sistema verifica que los datos requeridos fueron ingresados
    if nombre == "":
        error = "Se debe ingresar un nombre"
        return error

    if descripcion == "":
        error = "Se debe ingresar una descripcion"
        return error

    #El sistema verifica que se haya seleccionado al menos un permiso
    if len(permisos) == 0: #No selecciono ningun permiso
        error = "Debe seleccionar al menos un permiso"
        return error

    #El sistema verifica que el nombre del rol sea unico en el proyecto
    nombre_proyecto = session['nombre_proyecto']
    id_rol_seleccionado = int(session['id_rol_seleccionado'])

    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()

    fases = proyecto.fases

    for fase in fases:
        roles = fase.roles
        for rol in roles:
            if rol.nombre == nombre and rol.id != id_rol_seleccionado:
                error = "El nombre debe ser unico en el proyecto"
                break
    return error

def modificar_rol(nombre, descripcion, observacion, fase, permisos):
    """Realiza la modificacion del rol seleccionado en la base de 
    datos
    @param nombre: Nombre del rol modificado
    @param descripcion: Descripcion del rol modificado
    @param observacion: Observacion del rol modificado
    @param fase: Fase del rol modificado
    @param permisos: Lista de permisos del rol"""
    
    try:
        fecha_actual = datetime.now()
        id_usuario = session['id_usuario']
        usuario = db_session.query(Usuario).filter_by\
        (id_usuario=id_usuario).one()

        id_rol = int(session['id_rol_seleccionado'])
        rol = db_session.query(Rol).filter_by(id=id_rol).one()

        #Se borran los permisos actuales, para luego cargar los que 
        #vienen en la lista permisos
        continuar = True

        #Se verifica que la lista de permisos no este vacio
        if (len(rol.permisos) == 0):
            continuar = False

        while continuar:
            viejo_perm = rol.permisos[0]
            perm = db_session.query(Permiso).filter_by\
            (id=viejo_perm.id).one()
            rol.permisos.remove(perm)

            if (len(rol.permisos) == 0):
                continuar = False

        for nuevo_perm in permisos:
            perm = db_session.query(Permiso).filter_by\
            (id=int(nuevo_perm)).one()
            rol.permisos.append(perm)

        rol.nombre = nombre
        rol.descripcion = descripcion
        rol.observacion = observacion
        rol.fk_fase = int(fase)
        rol.fecha_modificacion = fecha_actual
        rol.usuario_modificacion = usuario.id

        db_session.add(rol)
        db_session.flush()
        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return "OK"

def buscar_roles_proyecto (cadena, campo):
    """Realiza la busqueda de roles de acuerdo al filtro seleccionado
    (nombre, descripcion, observacion) y devuelve las conincidencias
    encontradas.
    @param cadena: indica el dato que se quiere buscar
    @param campo: indica por cual campo se va a buscar
    @return items: retorna la lista con las coincidencias encontadas"""
    
    items = []
    
    nombre_proyecto = session["nombre_proyecto"]
        
    proyecto = db_session.query(Proyecto).filter_by(nombre = \
    nombre_proyecto).one()
    
    fases = proyecto.fases
    
    if campo == "todos":
        for fase in fases:
            roles = db_session.query(Rol).filter_by(\
            fk_fase=fase.id).filter(or_(\
            func.lower(Rol.nombre).contains(cadena),\
            func.lower(Rol.descripcion).contains(cadena),\
            func.lower(Rol.observacion).contains(cadena))).all()
            for rol in roles:
                item = dict(nombre=rol.nombre, \
                descripcion=rol.descripcion, \
                observacion=rol.observacion, fase=fase.nombre)

                items.append(item)
                
    if campo == "nombre":
        for fase in fases:
            roles = db_session.query(Rol).filter_by(fk_fase=fase.id).\
            filter(func.lower(Rol.nombre).contains(cadena)).all()
            for rol in roles:
                item = dict(nombre=rol.nombre, \
                descripcion=rol.descripcion, \
                observacion=rol.observacion, fase=fase.nombre)

                items.append(item)
        
    if campo == "descripcion":
        for fase in fases:
            roles = db_session.query(Rol).filter_by(fk_fase=fase.id).\
            filter(func.lower(Rol.descripcion).contains(cadena)).all()
            for rol in roles:
                item = dict(nombre=rol.nombre, \
                descripcion=rol.descripcion, \
                observacion=rol.observacion, fase=fase.nombre)

                items.append(item)
        
    if campo == "observacion":
        for fase in fases:
            roles = db_session.query(Rol).filter_by(fk_fase=fase.id).\
            filter(func.lower(Rol.observacion).contains(cadena)).all()
            for rol in roles:
                item = dict(nombre=rol.nombre, \
                descripcion=rol.descripcion, \
                observacion=rol.observacion, fase=fase.nombre)

                items.append(item)
                
    if campo == "fase":
        for fase in fases:
            roles = db_session.query(Rol).filter_by(fk_fase=fase.id).all()
            if cadena in fase.nombre:
                for rol in roles:
                    item = dict(nombre=rol.nombre, \
                    descripcion=rol.descripcion, \
                    observacion=rol.observacion, fase=fase.nombre)

                    items.append(item)
    
    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def validaciones_eliminar_roles(seleccionados):
    """Valida que sea seleccionado al menos un rol
    @param seleccionados: recibe la lista de roles que fueron 
                          seleccionados.
    @return error: retorna un mensaje indicando si no se ha seleccionado
                    al menos un rol
    @return error: mensaje de error en caso de no pasar las validacione"""
                    
    error = None
    if len(seleccionados) == 0: #No selecciono ningun rol
        error = "Debe seleccionar al menos un rol"
        
    return error
   
def eliminar_rol(seleccionados):
    """Elimina el rol, previamente verifica que el rol no tenga asociado
    algun usuario
    @param seleccionados: recibe la lista de roles que fueron 
                          seleccionados.
    @return error: en caso que el rol seleccionado tenga asignado un usuario"""
    
    try:
        for elemento in seleccionados:
            rol = db_session.query(Rol).filter_by(id=int(elemento)).one()
            if len(rol.usuarios)==0:
                db_session.delete(rol)
                db_session.flush()
            else:
                db_session.rollback()
                error = "El rol '" + rol.nombre + "' debe ser desasignado de todos los usuarios antes de eliminarse"
                return error
        db_session.commit()      
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message
    
    return "OK"
